package com.koron.common.core.util.message;

import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.business.datadict.utils.DataDictTool;
import com.koron.common.core.business.message.bean.dto.AccountPhone;
import com.koron.common.core.business.message.bean.dto.MessageTopicDto;
import com.koron.common.core.business.message.bean.po.MessageHistoryPo;
import com.koron.common.core.business.message.bean.po.MessageTemplatePo;
import com.koron.common.core.business.message.service.MessageHistoryService;
import com.koron.common.core.business.message.service.MessageTopicService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.qywx.QywxMessageProperties;
import com.koron.common.core.util.qywx.QywxMessageUtil;
import com.koron.common.core.util.sms.IMobileMessageSender;
import com.koron.common.core.util.sms.MobileMessageVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.ADOConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName MessageUtil
 * @description 消息发送工具类 目前两种方式 短息+企业微信
 * @Author zhouj
 * @Date 2022/3/14 15:10
 */
@RefreshScope
@Slf4j
@Component
public class MessageUtil {

    @Autowired
    MessageTopicService messageTopicService;

    @Autowired
    MessageHistoryService historyService;

    @Autowired
    QywxMessageUtil qywxMessageUtil;

    @Autowired
    QywxMessageProperties qywxMessageProperties;

    @Autowired
    IMobileMessageSender iMobileMessageSender;

    //前端路由前缀 http://10.11.228.110:8080/#/
    @Value("${eam.routePath:null}")
    private String routePath;

    @Value("${eam.mobileRoutePath:null}")
    private String mobileRoutePath;

    /*
     * 功能描述 发送短信消息
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param template 模板 目标人 handler args 模板参数
     *        模板参数带有链接的,以{{}}标识,会自动替换成链接
     * @return
     */
    public void sendMessageWithTemplate(String topicCode, String url, String handler, String... args) {

        //获取发送的模板
        List<MessageTemplatePo> templatePoList = getTemplate(topicCode);
        if (templatePoList == null) {
            return;
        }
        for (MessageTemplatePo templatePo : templatePoList) {

            if (!templatePo.getStatus()) {
                continue;
            }

            //处理好模板及参数  {{ 替换为 < a href="">  }}替换为</a>
            String template = templatePo.getTemplate();

            String template_f = args.length != 0 ? String.format(template, args) : template;

            String content = template_f;

            //url不为空进行链接{{}}标识的替换
            if (!StringUtils.isEmpty(url)) {

                String replace_1 = template_f.replace("{{", getLeft(url));

                content = replace_1.replace("}}", getRight());
            }

            String notifyType = templatePo.getNotifyType();

            switch (notifyType) {
                case "sms":
                    sendSms(topicCode, handler, content);
                    break;
                case "qywx":
                    sendQywxText(topicCode, handler, content);
                    break;
            }
        }
    }

    /*
     * 功能描述 通过消息通知编号获取消息模板列表  企业微信及短信模板 过滤掉不在适用范围,关闭状态
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param topicCode 消息模板编号
     * @return List<MessageTemplatePo>
     */
    public List<MessageTemplatePo> getTemplate(String topicCode) {

        //根据主题编码查找 发送方式+模板内容 记录下发送是否成功 时间等
        MessageTopicDto topicDto = ADOConnection.runTask(messageTopicService, "queryByCode", MessageTopicDto.class, topicCode);

        if (topicDto == null) {
            log.info("找不到消息模板：" + topicCode);
            return null;
        }

        //获取适用范围
        String scope = topicDto.getScope();

        if (StringUtils.isEmpty(scope) || !scope.contains(getCurrDs())) {
            log.info("{}没有在{}适用:", topicDto.getTopicName(), getCurrDs());
            return null;
        }

        List<MessageTemplatePo> templatePoList = topicDto.getTemplatePoList();

        templatePoList.removeIf(next -> !next.getStatus());
        log.info("MessageUtil:templatePoList={}",templatePoList);
        return CollectionUtils.isEmpty(templatePoList) ? new ArrayList<>() : templatePoList;
    }

    //替换{{
    private String getLeft(String url) {
        return "<a href=\"" + url + "\">";
    }

    //替换}}
    private String getRight() {
        return "</a>";
    }

    public String generateQywxHref(String businessCode, String... args) {
        String eamHref = generateEamHref(businessCode, args);
        String eamRedirectHref = generateEamRedirectHref(eamHref);
        String qywxHref = generateQywxHref(eamRedirectHref);
        return qywxHref;
    }

    /*
     * 功能描述 构造企业微信携带用户信息链接
     * @author zhouj
     * @date 2022/3/18 14:10
     * @param [eam_href] eam重定向地址
     * @return java.lang.String
     */
    public String generateQywxHref(String eam_href) {

        /*
        https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww1736e9ae98ad76c9&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=1000294&state=STATE#wechat_redirect
        appid	是	企业的CorpID
        redirect_uri	是	授权后重定向的回调链接地址，请使用urlencode对链接进行处理
        response_type	是	返回类型，此时固定为：code
        scope	是	应用授权作用域。此时固定为：snsapi_base
        agentid	否	企业应用的id。
        注意redirect_uri的域名必须与该应用的可信域名一致。
        state	否	重定向后会带上state参数，企业可以填写a-zA-Z0-9的参数值，长度不可超过128个字节
        #wechat_redirect	是	终端使用此参数判断是否需要带上身份信息*/
        //首先构造连接
        String encodeUrl = null;
        try {
            encodeUrl = URLEncoder.encode(eam_href, "utf-8");

        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }

        String corpId = qywxMessageProperties.getCorpId();
        Integer agentId = qywxMessageProperties.getAgentId();


        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + corpId + "&redirect_uri=" + encodeUrl + "&response_type=code&scope=SCOPE&agentid=" + agentId + "&state=STATE#wechat_redirect";

        return url;

    }

    /*
     * 功能描述 企业微信点击链接重定向的完整链接
     * @author zhouj
     * @date 2022/3/18 14:09
     * @param [eam_href] 目标地址
     * @return java.lang.String
     */
    public String generateEamRedirectHref(String eam_href) {

        String eamRedirectUrl = getEamRedirectUrl();

        String encodeUrl = null;
        try {
            encodeUrl = URLEncoder.encode(eam_href, "utf-8");

        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }

        return eamRedirectUrl + encodeUrl;

    }

    /*
     * 功能描述 获取eam配置的业务路由转换的完整路径
     * @author zhouj
     * @date 2022/3/18 14:08
     * @param [businessCode, args] 业务编码 对应的占位符参数
     * @return java.lang.String
     */
    public String generateEamHref(String businessCode, String... args) {

        Map<String, String> cond = DataDictTool.getDataDictByCode("publicDictionary", "module_code");

        String route_suf = cond.get(businessCode);
        Assert.hasText(route_suf, "该模板编号"+ businessCode +"不存在");
        String route_format = String.format(route_suf, args);
        return getRoutePath() + route_format + "&currDs=" + getCurrDs();

    }

    public String generateEamIdHref(String businessCode,  String arg) {

        Map<String, String> cond = DataDictTool.getDataDictByCode("publicDictionary", "module_code");

        String route_suf = cond.get(businessCode);
        log.info("MessageUtil:route_suf={}",route_suf);
        Assert.hasText(route_suf, "该模板编号"+ businessCode +"不存在");
        String s = route_suf.contains("%s") ?
                route_suf.replaceFirst("%s.*", arg)
                : route_suf.contains("?") ?
                route_suf + "&id=" + arg
                : route_suf + "?id=" + arg;

        return getRoutePath() + s + "&currDs=" + getCurrDs();

    }

    public String generateMobileIdHref(String... mobileArgs){
        Map<String, String> cond = DataDictTool.getDataDictByCode("publicDictionary", "module_code");
        String mobileUrl = cond.get("transmit_mobile");
        if (StringUtils.isEmpty(mobileUrl)){
            return null;
        }
        //String mobileUrl = "http://localhost:8080?id=%s&title=%s&account=%s&createBy=%s&processCode=%s&modelName=%s";
        String formatMobileUrl = String.format(mobileUrl, mobileArgs);
        return formatMobileUrl;
    }

    public String generateMobileEamIdHref(String businessCode,  String arg) {

        Map<String, String> cond = DataDictTool.getDataDictByCode("publicDictionary", "module_code");

        String route_suf = cond.get(businessCode);
        log.info("MessageUtil:route_suf={}",route_suf);
        Assert.hasText(route_suf, "该模板编号"+ businessCode +"不存在");
        String s = route_suf.contains("%s") ?
                route_suf.replaceFirst("%s.*", arg)
                : route_suf.contains("?") ?
                route_suf + "&id=" + arg
                : route_suf + "?id=" + arg;

        return getMobileRoutePath() + s + "&currDs=" + getCurrDs();

    }


    /*
     * 功能描述 发送企业微信消息
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param account 账号(多个逗号分割) 内容 content
     * @return
     */
    public void sendQywxText(String topicCode, String handler, String content) {

        if(sendOrNot("qywx")){
            log.info("未开启企业微信发送开关");
            return;
        }

        Assert.isTrue(StringUtils.isNotEmpty(handler),"请选择需要通知的对象！");

        String r_account = handler.replaceAll("[,;&]", "|");

        Boolean status = false;

        try {
            qywxMessageUtil.sendText(r_account, content);
            status = true;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } catch (IllegalArgumentException e){
            log.error(e.getMessage(), e);
        }
        record(topicCode, status, MessageNotifyType.qywx.getCode(), handler, content);
    }

    /*
     * 功能描述 发送企业微信消息
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param account 账号(多个逗号分割) 内容 content
     * @return
     */
    public void sendQywxText(String handler, String content) {

        sendQywxText(null, handler, content);
    }

    public void sendSms(String handler, String content) {
        sendSms(null, handler, content);
    }

    /*
     * 功能描述 发送短信消息
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param account 账号(多个逗号分割) 内容 content
     * @return
     */
    public void sendSms(String topicCode, String handler, String content) {

        if(sendOrNot("sms")){
            log.info("未开启短信发送开关");
            return;
        }

        //传过来的handler如果是账号 需要将其转换为手机号

        Boolean status = false;

        List<MobileMessageVO> mobileMessageVos = new ArrayList<>();

        String[] split = handler.split(",");

        List<AccountPhone> accountPhones = ADOConnection.runTask(messageTopicService, "queryPhoneByAccountList", List.class, Arrays.asList(split));

        Assert.isTrue(CollectionUtils.isNotEmpty(accountPhones),"请选择需要通知的对象");

        List<String> phoneList = accountPhones.stream().map(AccountPhone::getPhone).collect(Collectors.toList());

        for (String phone : phoneList) {
            MobileMessageVO mobileMessageVO = new MobileMessageVO();

            mobileMessageVO.setReceiverPhone(phone);
            mobileMessageVO.setMessageContent(content);
            mobileMessageVos.add(mobileMessageVO);
        }
        try {
            iMobileMessageSender.sendMessage(mobileMessageVos);
            status = true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        record(topicCode, status, MessageNotifyType.sms.getCode(), handler, content);

    }

    /*
     * 功能描述 消息发送记录
     * @author zhouj
     * @date 2022/3/14 16:04
     * @param template 模板 目标人 handle args 模板参数
     * @return
     */
    public void record(String topicCode, Boolean status, String notifyType, String handler, String content) {

        List<AccountPhone> accountPhones = ADOConnection.runTask(messageTopicService, "queryPhoneByAccountList", List.class, Arrays.asList(handler.split(",")));
        if (CollectionUtils.isEmpty(accountPhones)) {
            log.error("没有找到该账号信息:{}", handler);
            return;
        }
        List<String> nameList = accountPhones.stream().map(AccountPhone::getName).collect(Collectors.toList());

        MessageHistoryPo historyPo = new MessageHistoryPo();
        historyPo.setHandler(handler);
        historyPo.setHandlerName(String.join(",", nameList));
        historyPo.setNotifyType(notifyType);
        historyPo.setContent(content);
        historyPo.setStatus(status);
        historyPo.setAppMark(getCurrDs());
        historyPo.setTopicCode(topicCode);

        ADOConnection.runTask(getCurrDs(), historyService, "insertOrUpdate", Integer.class, historyPo);

    }

    //获取当前水司mark
    private String getCurrDs() {
        return ThreadLocalContext.getApp().getMark();
    }

    //是否发送消息判断
    private boolean sendOrNot(String messageType) {

        Map<String, String> configByCode = ConfigInfoTool.getConfigByCode("system", "message_global_switch");

        String orDefault = configByCode.getOrDefault(messageType, "0");

        return orDefault.equals("0");
    }

    public String getEamRedirectUrl() {
        return qywxMessageProperties.getEamRedirectUrl();
    }

    public String getRoutePath() {
        return routePath;
    }

    public String getMobileRoutePath(){
        return mobileRoutePath;
    }
}
